<!-- #layout name=default -->
<div id="main" class="code-container">
  <div class="code-tree">
    <div>
      <input class="code-search" placeholder="search" v-model="keyword" />
    </div>
    <div>
      <template v-for="code in filtedCodes">
        <div
          v-if="typeof(code)=='object'"
          :key="code.id"
          class="code-item"
          @click="currentCode=code"
          :class="{'select-code-item':code.id==currentCode.id}"
        >
          {{code.name}}
        </div>
        <h4 :key="code" v-else>{{code}}</h4>
      </template>
    </div>
  </div>
  <div class="ctrl-bar navbar navbar-default">
    <button class="btn btn-default blue" v-if="end" @click="startSession">
      <i class="glyphicon glyphicon-play"></i> <span>Start debugging</span
      ><span>(F5)</span>
    </button>

    <button class="btn btn-default" v-else @click="onStep('None')">
      <i class="glyphicon glyphicon-arrow-right"></i> <span>Continue</span
      ><span>(F8)</span>
    </button>

    <button class="btn btn-default" @click="onStep('Into')">
      <i class="glyphicon glyphicon-log-in"></i> <span>Step into</span
      ><span>(F11)</span>
    </button>
    <button
      class="btn btn-default"
      @click.stop.prevent.keyup.121="onStep('Over')"
    >
      <i class="glyphicon glyphicon-new-window"></i> <span>Step over</span
      ><span>(F10)</span>
    </button>
    <button class="btn btn-default" @click="onStep('Out')">
      <i class="glyphicon glyphicon-log-out"></i> <span>Step out</span
      ><span>(Shift + F11)</span>
    </button>
    <div style="position: absolute; right: 0">
      <a
        v-if="currentCode&&currentCode.previewUrl"
        target="blank"
        class="btn"
        @click="showPreview(currentCode.previewUrl)"
        >Preview</a
      >
      <a
        target="blank"
        class="btn blue"
        v-if="currentCode"
        :href="Kooboo.Route.Get(Kooboo.Route.Code.EditPage, {
            id: currentCode.id
        })"
        >Edit</a
      >
      <button class="btn btn-default" @click="getCode(currentCode)">
        <i class="fa fa-refresh"></i>&nbsp;<span>Reload</span>
      </button>
    </div>
  </div>

  <div class="code-editor" :style="{bottom:showPreviewPanel?'310px':'5px'}">
    <table>
      <tr v-for="(line,index) in lines">
        <td
          class="breackpoint"
          :class="{'checked-bk':isBreakpoint(index+1)}"
          @click="checkBreackpoint(index+1)"
        >
          <span><i></i>{{index+1}}</span>
        </td>
        <td
          class="code-line"
          :class="{'current-executing':isExecuting(index+1)&&!end}"
        >
          <code>{{line}}</code>
        </td>
      </tr>
    </table>
  </div>
  <div class="execute-code">
    <h6>Execute code</h6>
    <div class="terminal">
      <span>></span>
      <input
        v-model.trim="code"
        @keydown.enter="executeCode"
        @keydown.up="executeHistoryUp"
        @keydown.down="executeHistoryDown"
        placeholder="Enter code"
      />
    </div>
    <div>
      <template v-for="item in codeResults">
        <template v-if="typeof(item)=='array'||typeof(item)=='object'">
          <v-json-tree :json-data="item" full-markup />
        </template>
        <template v-else>
          <p>{{item}}</p>
        </template>
      </template>
    </div>
  </div>

  <div class="variables">
    <template v-if="exception">
      <h6>Exception</h6>
      <v-json-tree v-if="debugInfo" :json-data="exception" full-markup />
    </template>
    <template v-else>
      <h6>Variables</h6>
      <v-json-tree
        v-if="debugInfo"
        :json-data="debugInfo.variables"
        full-markup
      />
    </template>
  </div>

  <div class="preview-panel" v-if="showPreviewPanel">
    <div class="url-ctrl">
      <input v-model="previewUrl" @keydown.enter="goToPreview" />
      <i
        class="fa fa-refresh"
        @click="goToPreview"
        style="margin-right: 10px"
      ></i>
      <i class="fa fa-close" @click="showPreviewPanel=false"></i>
    </div>
    <iframe :src="iframeUrl"> </iframe>
  </div>
</div>

<script>
  Kooboo.loadJS(["/_Admin/Scripts/lib/vue-json-tree.js"]);
  Vue.component("v-json-tree", vJsonTree);

  new Vue({
    el: "#main",
    data: function () {
      return {
        keyword: "",
        codes: [],
        currentCode: null,
        lines: [],
        breackpoints: [],
        debugInfo: null,
        end: false,
        code: "",
        codeResults: [],
        executeHistory: [],
        executeHistoryBak: [],
        exception: null,
        showPreviewPanel: false,
        previewUrl: "",
        iframeUrl: "",
      };
    },
    mounted: function () {
      this.getCodes();

      var me = this;
      document.onkeydown = function (e) {
        switch (e.keyCode) {
          case 116: //F8
            e.preventDefault();
            me.startSession();
            break;
          case 119: //F8
            e.preventDefault();
            me.onStep("None");
            break;
          case 122: //F11
            e.preventDefault();
            if (e.shiftKey) {
              me.onStep("Out");
            } else {
              me.onStep("Into");
            }
            break;
          case 121: //F10
            e.preventDefault();
            me.onStep("Over");
            break;
        }
      };

      this.keepSessionLive();
    },
    watch: {
      currentCode(value) {
        this.getCode(value);
      },
    },
    computed: {
      filtedCodes() {
        var me = this;
        var tree = {};

        var codes = this.codes.filter(function (f) {
          return f.name.indexOf(me.keyword) > -1;
        });

        for (let i = 0; i < codes.length; i++) {
          var code = codes[i];
          if (!tree[code.codeType]) tree[code.codeType] = [];
          tree[code.codeType].push(code);
        }

        var result = [];

        for (var key in tree) {
          result.push(key);
          var list = tree[key];
          for (var j = 0; j < list.length; j++) {
            result.push(list[j]);
          }
        }

        return result;
      },
    },
    methods: {
      checkBreackpoint: function (line) {
        var me = this;
        if (!me.currentCode || !me.currentCode.id) return;

        Kooboo.Debugger.setBreakpoint({
          point: {
            codeId: me.currentCode.id,
            line: line,
          },
          isCurrent: false,
        }).then(function (rsp) {
          me.breackpoints = rsp.model;
        });
      },
      isBreakpoint: function (line) {
        var me = this;
        if (!me.currentCode || !me.currentCode.id) return;

        return (
          me.breackpoints.filter(function (f) {
            return f.line == line && f.codeId == me.currentCode.id;
          }).length > 0
        );
      },
      isExecuting(line) {
        var me = this;
        if (!me.currentCode || !me.currentCode.id || !me.debugInfo) return;
        return line == me.debugInfo.currentLine;
      },
      keepSessionLive: function () {
        var me = this;
        setInterval(function () {
          Kooboo.Debugger.getSession().then(function (rsp) {
            me.breackpoints = rsp.model.breakLines;
            me.debugInfo = rsp.model.debugInfo;
            me.exception = rsp.model.exception;
            me.end = rsp.model.end;
            if (me.exception) me.end = true;

            if (!me.end && me.debugInfo && rsp.model.currentCodeId) {
              me.currentCode = me.codes.filter(function (f) {
                return f.id == rsp.model.currentCodeId;
              })[0];
            }
          });
        }, 500);
      },
      startSession: function () {
        var me = this;
        Kooboo.Debugger.startSession().then(function (rsp) {
          me.avtive = true;
        });
      },
      getCodes: function () {
        var me = this;
        Kooboo.Code.getListByType({
          codeType: "all",
        }).then(function (rsp) {
          me.codes = rsp.model;
          if (!me.currentCode) me.currentCode = me.codes[0];
        });
      },
      onStep(step) {
        Kooboo.Debugger.step({
          action: step,
        });
      },
      getCode: function (value) {
        if (!value) return;
        var me = this;
        Kooboo.Code.getEdit({
          id: value.id,
          codetype: value.codeType,
        }).then(function (rsp) {
          if (!rsp.model || !rsp.model.body) return;
          me.lines = rsp.model.body.split("\n");
        });
      },
      executeCode: function () {
        var me = this;
        if (!me.code) return;
        var code = me.code;
        me.code = "";
        Kooboo.Debugger.execute({
          jsStatement: code,
        }).then(function (rsp) {
          if (rsp.success) {
            var result = rsp.model;

            try {
              result = JSON.parse(rsp.model);
            } catch {}

            me.codeResults.unshift(result);
          } else {
            me.codeResults.unshift(rsp.messages);
          }
          me.codeResults.unshift(code);
        });
        me.executeHistory.push(code);
        me.executeHistoryBak = [];
      },
      executeHistoryUp: function () {
        var me = this;
        var code = me.executeHistory.pop();
        if (code) {
          me.executeHistoryBak.push(me.code);
          me.code = code;
        }
      },
      executeHistoryDown: function () {
        var me = this;
        var code = me.executeHistoryBak.pop();
        if (code) {
          me.executeHistory.push(me.code);
          me.code = code;
        }
      },
      showPreview: function (url) {
        var me = this;
        if (
          location.protocol.toLowerCase().startsWith("https") &&
          !url.toLowerCase().startsWith("https")
        ) {
          window.open(url);
          me.showPreviewPanel = false;
        } else {
          me.showPreviewPanel = true;
          me.previewUrl = url;
          me.goToPreview();
        }
      },
      goToPreview: function () {
        var me = this;
        me.iframeUrl = "";
        me.$nextTick(function () {
          me.iframeUrl = me.previewUrl;
        });
      },
    },
  });
</script>

<style>
  .code-container {
    position: fixed;
    left: 0;
    right: 0;
    top: 46px;
    bottom: 0;
    margin: 0 !important;
    padding: 0 !important;
  }

  .code-tree {
    width: 200px;
    border-right: 1px solid #ddd;
    background-color: #f1f1f1;
    overflow-x: hidden;
    overflow-y: auto;
    position: absolute;
    left: 0;
    bottom: 0;
    top: 0;
  }

  .code-search {
    width: 100%;
    outline-width: 0;
    border-width: 0;
    height: 35px;
    padding: 5px;
    border-bottom: 1px solid #ddd;
  }

  .code-item {
    line-height: 20px;
    padding: 5px;
    cursor: pointer;
  }

  .select-code-item {
    background-color: #ddd;
  }

  .code-item:hover {
    background-color: rgba(221, 221, 221, 0.541);
  }

  .breackpoint {
    vertical-align: top;
    background-color: #f1f1f1;
    word-break: keep-all;
  }

  .breackpoint span {
    display: flex;
    align-items: center;
    justify-content: left;
    padding: 2px 5px;
    cursor: pointer;
  }

  .breackpoint span i {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    transition: opacity 0.3s ease-in-out;
    opacity: 0;
    background-color: red;
    margin-right: 3px;
  }

  .breackpoint:hover i {
    opacity: 0.5;
  }

  .checked-bk i {
    opacity: 0.9 !important;
  }

  .code-line {
    word-break: break-all;
    background-color: #fff;
    padding: 0 5px;
    width: 100%;
    display: flex;
    align-items: center;
  }

  .current-executing {
    background-color: yellow;
  }

  code {
    color: black;
    background-color: transparent;
    word-break: break-all;
    white-space: pre-wrap;
  }

  .ctrl-bar {
    position: absolute;
    top: 5px;
    left: 205px;
    right: 5px;
    padding: 0 5px;
    display: flex;
    align-items: center;
  }

  .code-editor {
    position: absolute;
    bottom: 5px;
    top: 55px;
    left: 205px;
    right: 310px;
    overflow: auto;
    outline: #f1f1f1 1px solid;
  }

  .execute-code {
    position: absolute;
    bottom: 0;
    top: 55px;
    right: 5px;
    width: 300px;
    height: 400px;
    outline: #f1f1f1 1px solid;
    padding: 3px;
    overflow-y: auto;
    word-break: break-all;
  }

  .preview-panel {
    position: absolute;
    outline: #f1f1f1 1px solid;
    height: 300px;
    bottom: 5px;
    left: 205px;
    right: 310px;
  }

  .preview-panel iframe {
    width: 100%;
    height: 100%;
    border: 0;
  }

  .url-ctrl {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 5px;
  }

  .url-ctrl input {
    outline: 0;
    border: 0;
    border-bottom: 1px solid #f1f1f1;
    width: 100%;
    padding: 3px;
    margin: 3px;
  }

  .variables {
    position: absolute;
    bottom: 5px;
    top: 460px;
    right: 5px;
    width: 300px;
    outline: #f1f1f1 1px solid;
    padding: 3px;
    overflow-y: auto;
    word-break: break-all;
  }

  .terminal {
    display: flex;
  }

  .terminal input {
    outline-width: 0;
    border: 0;
    width: 100%;
    position: relative;
  }

  .terminal span {
    font-size: large;
    animation: blink 0.5s alternate ease-in-out infinite;
  }

  @keyframes blink {
    0% {
      opacity: 0;
    }

    100% {
      opacity: 1;
    }
  }
</style>
